<?php

namespace lico\Tool;

class Apidoc
{

    /**
     * 忽视函数
     */
    protected $ignoreMethod = [
        '__construct',
        '__call',
        '__set',
        '__get',
        '__autoload',
        '__isset',
        '__unset',
        '__destruct',
        '__clone',
        '__toString',
        '__sleep',
        '__wakeup',
        '__callStatic',
        '__invoke',
    ];
    /**
     * 文档配置
     */
    protected $docConfig = [
        'type' => 'json', //php,json,html
        'folder' => '',
        'fileName' => 'doc',
    ];

    /**
     * 生成接口文档
     */
    public function buildApiDocument($class)
    {
        // p($class);

        $methodHandler = $this->getMethodHandler($class);

        $map = $this->getExegesisMap($methodHandler);

        $this->save($map);

        return $map;
    }

    /**
     * 获取反射方法
     */
    public function getMethodHandler($class)
    {
        $classHandler = new \ReflectionClass($class); //p($classHandler);
        $methodHandler = $classHandler->getMethods(\ReflectionMethod::IS_PUBLIC); //p($methodHandler);
        return $methodHandler;
    }

    /**
     * 获取class-注释字典
     */
    public function getExegesisMap($methodHandler)
    {
        $map = [];
        foreach ($methodHandler as $key => $value) {
            if (in_array($value->name, $this->ignoreMethod)) {
                continue;
            }

            $doc = $value->getDocComment();
            $docArr = $this->parse($doc);

            if (!isset($map[$value->class])) {
                $map[$value->class] = [];
            }
            $map[$value->class][$value->name] = $docArr;
        }
        return $map;
    }

    /**
     * 解析
     */
    public function parse($comment)
    {
        // d($comment);
        $docResult = [];
        if ($comment) {
            $expr = '#^/\*\*(.*)\*/#s';
            preg_match_all($expr, $comment, $matchs); //p($matchs);
            $commentLine = end($matchs);

            $line = '#^\s*\*(.*)#m';
            preg_match_all($line, current($commentLine), $doc); // p($doc);
            $docArr = end($doc);

            $docResult['name'] = current($docArr);
            $docResult['param'] = [];
            foreach ($docArr as $key => $value) {
                if ($param = strpos($value, '@param')) {
                    $docResult['param'][] = trim(substr($value, $param + 6));
                }
                if ($return = strpos($value, '@return')) {
                    $docResult['return'][] = trim(substr($value, $return + 7));
                }
            }

            return $docResult;
        } else {
            return $comment;
        }
    }

    /**
     * 写入文档
     */
    public function save($apiMap)
    {

        $type = $this->docConfig['type'];

        $class = __CLASS__ . '\\' . ucfirst($type);

        $handler = new $class;
        $res = $handler
            ->setConfig($this->docConfig)
            ->save($apiMap);

        echo '生成接口文档成功';
    }
}
